﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ActionCreatePointFamilyInstance.h"
#include "IDocument.h"
#include "IInstance.h"
#include "IWorkPlane.h"
#include "IHighlights.h"
#include "IModelView.h"
#include "IUiView.h"
#include "IPlane.h"
#include "ISelection.h"
#include "IUiDocument.h"
#include "IUserTransaction.h"
#include "IDocument.h"
#include "IReferencePlane.h"
#include "AlgorithmProject.h"
#include "IUiDocumentViewManager.h"
#include "UserTransactionGroupUtils.h"
#include "PickNodeReferenceOption.h"
#include "IGraphicsElementShape.h"
#include "IElementModelShape.h"
#include "IGraphicsBRepBody.h"
#include "GraphicsNodeUtils.h"
#include "IElementPosition.h"
#include "IPositionSingleAssociatedPlane.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace Sample;


ActionCreatePointFamilyInstance::ActionCreatePointFamilyInstance(const gcmp::ElementId& familyId, const std::wstring& familyType, bool needSetPrecision)
    : m_familyId(familyId)
    , m_familyType(familyType)
    , m_needSetPrecision(needSetPrecision)
{
}

ActionCreatePointFamilyInstance::~ActionCreatePointFamilyInstance()
{
}

void ActionCreatePointFamilyInstance::InitAction(IUiView* pCurrentView)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView != nullptr, L"GetCurrentUiView()为空", L"GDMP", L"2023-09-30");
    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    IDocument* pDoc = pUiDoc->GetDbDocument();
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();

    SetMouseTooltipMessage(GBMP_TR(L"请点击场景选择族实例放置的位置"));
}

void ActionCreatePointFamilyInstance::ActionCancelled()
{
    CleanupTempGraphicsShape();
    ActionBase::ActionCancelled();
}

bool ActionCreatePointFamilyInstance::OnMovePoint(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos)
{
    // 用于显示鼠标提示信息
    ActionBase::OnMovePoint(pCurrentView, pos);

    UpdateView();
    return true;
}

bool ActionCreatePointFamilyInstance::OnLButtonDown(IUiView* pCurrentView, const Vector3d& pos)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView, L"pCurrentView为空", L"GDMP", L"2023-09-30");
    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    IDocument* pDoc = pUiDoc->GetDbDocument();
    IModelView* pModelView = pCurrentView->GetModelView();
      
    OwnerPtr<IUserTransaction> opUt = IUserTransaction::Create(pDoc, GBMP_TR(L"创建GBMP普通点式族实例"));
          
    OwnerPtr<IPlane> opWorkPlane = pModelView->GetWorkPlane();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opWorkPlane, L"获取参照面失败", L"GDMP", L"2023-09-30");
         
    Vector2d projectPos2d;
    Vector3d projectPos3d;
    if (!AlgorithmProject::Project(pos, opWorkPlane.get(), projectPos2d, projectPos3d))
        return false;
      
    IInstance* pInstance = CreateInstanceByOnePoint(pDoc, m_familyId, m_familyType, L"点式族实例", pModelView->GetWorkPlaneId(), projectPos3d);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstance, L"pInstance为空", L"GDMP", L"2023-09-30");
      
    if (!opUt->Commit())
    {
        return false;
    }

    if (m_needSetPrecision)
    {
        OwnerPtr<IUserTransaction> opUt1 = IUserTransaction::Create(pDoc, GBMP_TR(L"设置离散精度"));
        {
            //设置族实例的离散精度
            IElementModelShape* pModelShape = pInstance->GetElementModelShape();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelShape, L"pModelShape为空", L"GDMP", L"2023-09-30");
            OwnerPtr<IGraphicsElementShape> opEleshape = pModelShape->TransferGraphicsElementShape();
            IGraphicsElementShape* pEleshape = opEleshape.get();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pEleshape, L"opEleshape为空", L"GDMP", L"2023-09-30");

            std::vector<OwnerPtr<IGraphicsBRepBody>> opBodies = GraphicsNodeUtils::GetGraphicsBRepBodies(pDoc, pEleshape);
            FOR_EACH_INDEX(index, opBodies)
            {
                IGraphicsBRepBody* curBody = opBodies[index].get();
                curBody->SetDistanceDiscreteEpsilon(gcmp::Constants::MATH_PI / 10);
                GraphicsNodeUtils::ReplaceBRepBody(pDoc, pEleshape, index, TransferOwnership(opBodies[index]));
            }
            //将IGraphicsElementShape设置回去
            pModelShape->SetGraphicsElementShape(TransferOwnership(opEleshape));
            //设置离散精度结束
        }
        opUt1->Commit();
    }

    MarkFinishStatus(ActionFinishStatus::Successful);

    CleanupTempGraphicsShape();

    UpdateView();
    return true;
}

gcmp::IInstance* ActionCreatePointFamilyInstance::CreateInstanceByOnePoint(IDocument * pDocment, const ElementId & familyId,
    const std::wstring & familyType, const std::wstring& name, ElementId associatePlaneId, const Vector3d& position)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDocment, L"pDocument is nullptr", L"GDMP", L"2023-09-30");

    // create instance
    IInstance* pInstance = IInstance::Create(pDocment, familyId, familyType, name);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"faild to create family instance", L"GDMP", L"2023-09-30");

    // 设置关联平面
    if (associatePlaneId.IsValid())
    {
        IElementPosition::CreatePoint2dOnSingleAssociatedPlanePositionBehavior(pInstance, associatePlaneId, position, Vector3d::UnitX, Vector3d::UnitY);
        IElementPosition* posBehavior = pInstance->GetElementPosition();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(posBehavior, L"failed to create PositionBehavior ", L"GDMP", L"2023-09-30");

        IPositionSingleAssociatedPlane* posSinglePlane = quick_cast<IPositionSingleAssociatedPlane>(posBehavior->GetPositionAssociatedPlane());
        DBG_WARN_AND_RETURN_FALSE_UNLESS(posSinglePlane, L"posSinglePlane is nullptr", L"GDMP", L"2023-09-30");
        posSinglePlane->SetIsAllowRemoveAssociatedPlane(true);
    }

    return pInstance;
}
